Update TOML parser to pick up a bugfix
authorAlex Crichton <alex@alexcrichton.com>
Thu, 12 May 2016 18:44:00 +0000 (11:44 -0700)
committerAlex Crichton <alex@alexcrichton.com>
Sun, 12 Jun 2016 11:14:35 +0000 (04:14 -0700)
Cargo has previously accepted invalid TOML as valid, but this bugfix should fix
the problem. In order to prevent breaking all crates immediately toml-rs has a
compatibility mode which emulates the bug that was fixed. Cargo will issue a
warning if this compatibility is required to parse a crate.

Cargo.lock
Cargo.toml
src/cargo/ops/lockfile.rs
src/cargo/util/config.rs
src/cargo/util/toml.rs
tests/bad-config.rs
tests/path.rs

index 5e86f8e00983dc7842fa9f248f0f7862f1acb36f..b53479e307359618b6ea97268a0e580abcec3d28 100644 (file)
@@ -29,7 +29,7 @@ dependencies = [
  "tar 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
  "tempdir 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "term 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "toml 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)",
+ "toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)",
  "url 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -437,7 +437,7 @@ dependencies = [
 
 [[package]]
 name = "toml"
-version = "0.1.28"
+version = "0.1.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
index 4e6b627602bd7818f1297f89fbcd5242db5c6a8f..2c2194dd776ec12452f0747c90cd07300ab9115e 100644 (file)
@@ -41,7 +41,7 @@ semver = "0.2.2"
 tar = "0.4"
 tempdir = "0.3"
 term = "0.4.4"
-toml = "0.1"
+toml = "0.1.29"
 url = "1.1"
 winapi = "0.2"
 
index 41b6ac4b8d638dff8f8a09547b91890620433cc9..f24fe5bd5713a95923b5ca4dfac486a4d77cd949 100644 (file)
@@ -22,7 +22,7 @@ pub fn load_pkg_lockfile(pkg: &Package, config: &Config)
     }));
 
     (|| {
-        let table = toml::Value::Table(try!(cargo_toml::parse(&s, f.path())));
+        let table = toml::Value::Table(try!(cargo_toml::parse(&s, f.path(), config)));
         let mut d = toml::Decoder::new(table);
         let v: resolver::EncodableResolve = try!(Decodable::decode(&mut d));
         Ok(Some(try!(v.to_resolve(pkg, config))))
index b03b68379027657cd04133d38766197814a9c573..53ad520e609cdbc04e8d22a0b4a6e0aefa027ce5 100644 (file)
@@ -330,7 +330,9 @@ impl Config {
         try!(walk_tree(&self.cwd, |mut file, path| {
             let mut contents = String::new();
             try!(file.read_to_string(&mut contents));
-            let table = try!(cargo_toml::parse(&contents, &path).chain_error(|| {
+            let table = try!(cargo_toml::parse(&contents,
+                                               &path,
+                                               self).chain_error(|| {
                 human(format!("could not parse TOML configuration in `{}`",
                               path.display()))
             }));
@@ -717,7 +719,7 @@ pub fn set_config(cfg: &Config,
     };
     let mut contents = String::new();
     let _ = file.read_to_string(&mut contents);
-    let mut toml = try!(cargo_toml::parse(&contents, file.path()));
+    let mut toml = try!(cargo_toml::parse(&contents, file.path(), cfg));
     toml.insert(key.to_string(), value.into_toml());
 
     let contents = toml::Value::Table(toml).to_string();
index 82ea4533aca521587b5c4c10883a6f03563a2c80..27d7b14754db370398b3898a6305056f52bb53d7 100644 (file)
@@ -114,7 +114,7 @@ pub fn to_manifest(contents: &[u8],
     let contents = try!(str::from_utf8(contents).map_err(|_| {
         human(format!("{} is not valid UTF-8", manifest.display()))
     }));
-    let root = try!(parse(contents, &manifest));
+    let root = try!(parse(contents, &manifest, config));
     let mut d = toml::Decoder::new(toml::Value::Table(root));
     let manifest: TomlManifest = try!(Decodable::decode(&mut d).map_err(|e| {
         human(e.to_string())
@@ -154,15 +154,33 @@ pub fn to_manifest(contents: &[u8],
     }
 }
 
-pub fn parse(toml: &str, file: &Path) -> CargoResult<toml::Table> {
-    let mut parser = toml::Parser::new(&toml);
-    if let Some(toml) = parser.parse() {
+pub fn parse(toml: &str,
+             file: &Path,
+             config: &Config) -> CargoResult<toml::Table> {
+    let mut first_parser = toml::Parser::new(&toml);
+    if let Some(toml) = first_parser.parse() {
         return Ok(toml);
     }
+
+    let mut second_parser = toml::Parser::new(toml);
+    second_parser.set_require_newline_after_table(false);
+    if let Some(toml) = second_parser.parse() {
+        let msg = format!("\
+TOML file found which contains invalid syntax and will soon not parse
+at `{}`.
+
+The TOML spec requires newlines after table definitions (e.g. `[a] b = 1` is
+invalid), but this file has a table header which does not have a newline after
+it. A newline needs to be added and this warning will soon become a hard error
+in the future.", file.display());
+        try!(config.shell().warn(&msg));
+        return Ok(toml)
+    }
+
     let mut error_str = format!("could not parse input as TOML\n");
-    for error in parser.errors.iter() {
-        let (loline, locol) = parser.to_linecol(error.lo);
-        let (hiline, hicol) = parser.to_linecol(error.hi);
+    for error in first_parser.errors.iter() {
+        let (loline, locol) = first_parser.to_linecol(error.lo);
+        let (hiline, hicol) = first_parser.to_linecol(error.hi);
         error_str.push_str(&format!("{}:{}:{}{} {}\n",
                                     file.display(),
                                     loline + 1, locol + 1,
index b88ea2f6bfe4125ab6b7e3023c3603411daac204..63abb529f733810acec29d99fe57a4ef3c09e0ee 100644 (file)
@@ -479,3 +479,30 @@ warning: dependency (foo) specified without providing a local path, Git reposito
 to use. This will be considered an error in future versions
 "));
 }
+
+#[test]
+fn invalid_toml_historically_allowed_is_warned() {
+    let p = project("empty_deps")
+    .file("Cargo.toml", r#"
+        [package]
+        name = "empty_deps"
+        version = "0.0.0"
+        authors = []
+    "#)
+    .file(".cargo/config", r#"
+        [foo] bar = 2
+    "#)
+    .file("src/main.rs", "fn main() {}");
+
+    assert_that(p.cargo_process("build"),
+                execs().with_status(0).with_stderr("\
+warning: TOML file found which contains invalid syntax and will soon not parse
+at `[..]config`.
+
+The TOML spec requires newlines after table definitions (e.g. `[a] b = 1` is
+invalid), but this file has a table header which does not have a newline after
+it. A newline needs to be added and this warning will soon become a hard error
+in the future.
+[COMPILING] empty_deps v0.0.0 ([..])
+"));
+}
index 97cc213225a9df05452359fc208493299a406724..574851e93877f75a58f0b600d64ecb7bed21d4fb 100644 (file)
@@ -256,8 +256,10 @@ fn no_rebuild_dependency() {
             version = "0.5.0"
             authors = ["wycats@example.com"]
 
-            [[bin]] name = "foo"
-            [dependencies.bar] path = "bar"
+            [[bin]]
+            name = "foo"
+            [dependencies.bar]
+            path = "bar"
         "#)
         .file("src/foo.rs", r#"
             extern crate bar;
@@ -270,7 +272,8 @@ fn no_rebuild_dependency() {
             version = "0.5.0"
             authors = ["wycats@example.com"]
 
-            [lib] name = "bar"
+            [lib]
+            name = "bar"
         "#)
         .file("bar/src/bar.rs", r#"
             pub fn bar() {}